package com.wp.controller;


import com.wp.domain.SysLog;
import com.wp.service.SysLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * @author 卫鹏
 * @Description 日志通知
 * @createTime 2021年12月08日 20:50:00
 */
@Component
@Aspect
public class LogAop {

    //开始时间：
    private Date visitTime;
    //访问的类：
    private Class aClass;
    //访问的方法:
    private Method method;

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private SysLogService sysLogService;


    /**
     * 前置通知
     * 主要是：
     * 1. 获取开始时间
     * 2. 执行的类是哪一个
     * 3. 执行的是哪一个方法
     * <p>
     * 拦截 com.wp.controller的所有方法和参数
     */
    @Before("execution(* com.wp.controller.*.*(..))")
    public void doBefore(JoinPoint joinPoint) throws NoSuchMethodException {
        //前置时间一执行，就能直接获得开始时间[就是当前时间]:
        visitTime = new Date();
        //获取具体访问的class类对象:
        aClass = joinPoint.getTarget().getClass();
        //获取具体访问的方法名称：
        String methodName = joinPoint.getSignature().getName();
        //获取访问的方法参数：
        Object[] args = joinPoint.getArgs();
        /*
         * 获取具体执行的method对象
         */
        //判断方法是否无参:
        if (args == null || args.length == 0) {
            //获取无参的方法:
            method = aClass.getMethod(methodName);
        } else {
            /*
                若 方法有参数：
             */
            //获取class数组：
            Class[] classArgs = new Class[args.length];
            //遍历class数组:
            for (int i = 0; i < classArgs.length; i++) {
                //通过遍历，将每个class存储到数组中
                classArgs[i] = args[i].getClass();
            }
            //获取有参数的Method对象:
            method = aClass.getMethod(methodName, classArgs);
        }
    }


    /**
     * 后置通知
     */
    @After("execution(* com.wp.controller.*.*(..))")
    public void doAfter(JoinPoint jp) throws Exception {
        //获取操作后的时间:
        Long endTime = new Date().getTime();
        //获取访问的时长:
        Long interviewTime = endTime - visitTime.getTime();
        //url:
        StringBuilder url = new StringBuilder();

        /*
        获取url:
        */
        if (aClass != null && method != null && aClass != LogAop.class) {
            // 1. 获取类上的@RequestMapping("/***")
            //获取RequestMapping注解对象:
            RequestMapping requestMappingAnnotationClass = (RequestMapping) aClass.getAnnotation(RequestMapping.class);

            //判断requestMappingAnnotation是否不为null:
            if (requestMappingAnnotationClass != null) {
                //获取类上的注解：
                String valueClass = requestMappingAnnotationClass.value()[0];

                //将类上的注解 存入:
                url.append(valueClass);
            }
            //获取方法上的注解:
            RequestMapping requestMappingAnnotationMethod = method.getAnnotation(RequestMapping.class);
            if (requestMappingAnnotationMethod != null) {
                //获取方法上的注解：
                String valueMethod = requestMappingAnnotationMethod.value()[0];

                //将方法上的注解 存入:
                url.append(valueMethod);
            }
        }

        /*
         * 获取访问的ip的地址:
         */
        String ip = request.getRemoteAddr();

        //获取当前操作的用户:
        SecurityContext context = SecurityContextHolder.getContext();//从上下文获取当前登录的用户
        User user = (User) context.getAuthentication().getPrincipal();
        //获取用户名:
        String username = user.getUsername();

        //将日志相关信息封装到SysLog对象中:
        SysLog sysLog = new SysLog();
        //执行时长:
        sysLog.setExecutionTime(interviewTime);
        //ip地址:
        sysLog.setIp(ip);
        //执行方法:
        sysLog.setMethod("[类名:" + aClass.getName() + "] [方法名:" + method.getName() + "]");
        //url:
        sysLog.setUrl(url.toString());
        //用户名:
        sysLog.setUsername(username);
        //访问时间:
        sysLog.setVisitTime(visitTime);

        System.out.println(sysLog);

        /*
            调用Service完成添加操作:
         */
        //判断 访问的不是sysLog:
        if (!aClass.getName().equals("com.wp.controller.SysLogController")) {
            //调用service进行保存:
            sysLogService.save(sysLog);
        }

    }
}
